#include "logicmanager.h"
#include "network/client.h"
#include "network/netparam.h"
#include <QTimer>

#define PRINT_ENTER_FUN \
qDebug("C:  in LogicManager::%s", __func__)

static const int gPluseIntervalSecs = 30000;
static const int gRecordIntervalSecs = 3000;
static const char * gSendRecordTimeout = " [failed to deliver!!!]";
static const unsigned int gTimerIdMask = 0x000000ff;

LogicManager::LogicManager(QObject *parent) :
    QObject(parent)
{
    PRINT_ENTER_FUN;
    mXml = new xmlHandle;
    mListSet = new recordListSet;
    mSelf = new userInfo;
    mHash = new QHash<QString, QString>;

    mUserList = new QList<userInfo>;
    mMessage = new recordInfo;
    mXmlData = new QByteArray;
    mTimer = new QTimer(this); //visible deletion is needless

    mTimerList = new QList<QTimer *>;
    mRecordHash = new QHash<QTimer *, recordInfo>;
    mIpHash = new QHash<QTimer *, QString>;
    mIdHash = new QHash<unsigned short, QTimer *>;
    mId = 0;

    QObject::connect(mTimer, SIGNAL(timeout()), this, SLOT(onSendPulse()));
    QObject::connect(mXml, SIGNAL(sendStatus(QString, int)), this, SLOT(onSendStatus(QString, int)));
    QObject::connect(mXml, SIGNAL(sendUserList(QList<userInfo>)), this, SLOT(onSendUserList(QList<userInfo>)));
    QObject::connect(mXml, SIGNAL(sendRecordInfo(QString, recordInfo)), this, SLOT(onSendRecordInfo(QString, recordInfo)));
}

LogicManager::~LogicManager()
{
    PRINT_ENTER_FUN;
    if (mXml) {
        delete mXml;
    }
    if (mListSet) {
        delete mListSet;
    }
    if (mSelf) {
        delete mSelf;
    }
    if (mHash) {
        delete mHash;
    }
    if (mUserList) {
        mUserList->clear();
        delete mUserList;
    }
    if (mMessage) {
        delete mMessage;
    }
    if (mXmlData) {
        delete mXmlData;
    }
    if (mTimerList) {
        for (int i = 0; i < mTimerList->size(); ++i) {
            mTimerList->at(i)->stop();
            delete mTimerList->at(i);
        }
        mTimerList->clear();
        delete mTimerList;
    }
    if (mRecordHash) {
        delete mRecordHash;
    }
    if (mIpHash) {
        delete mIpHash;
    }
    if (mIdHash) {
        delete mIdHash;
    }
}

void LogicManager::onSendLogout()
{
    PRINT_ENTER_FUN;
    mXml->logoutToXml(*mXmlData);
    emit sendServerData(*mXmlData);
}

void LogicManager::onSendMessage(const QString & ip, const QString & message)
{

    if (++mId == 0) {
        ++mId;
    }
    qDebug("C:  in LogicManager::%s, ip:%s", __func__, ip.toLatin1().data());
    mMessage->setErrorCode(mId);
    mMessage->setName(mSelf->getName());
    mMessage->setContent(message);
    mXml->recordInfoToXml(*mXmlData, *mMessage);
    emit sendData(ip, *mXmlData);
    mListSet->insertRecordInfo(ip, *mMessage);
    const QList<recordInfo> * list = mListSet->getRecordList(ip);
    emit messageUpdate(ip, *list);

    QTimer * timer = new QTimer;
    mRecordHash->insert(timer, *mMessage);
    mIpHash->insert(timer, ip);
    mIdHash->insert(mId, timer);
    mTimerList->append(timer);
    QObject::connect(timer, SIGNAL(timeout()), this, SLOT(onRecordSendError()));
    timer->start(gRecordIntervalSecs);
}

void LogicManager::onRecordSendError()
{
    PRINT_ENTER_FUN;
    QTimer * timer = qobject_cast<QTimer *>(QObject::sender());
    timer->stop();
    if (mRecordHash->contains(timer) && mIpHash->contains(timer)) {
        recordInfo info = mRecordHash->value(timer);
        info.setErrorCode(-1);
        QString content = info.getContent();
        info.setContent(content.append(gSendRecordTimeout));
        QString ip = mIpHash->value(timer);
        mListSet->insertRecordInfo(ip, info);
        const QList<recordInfo> * list = mListSet->getRecordList(ip);
        emit messageUpdate(ip, *list);
        killTimer(timer);
        unsigned short id = mIdHash->key(timer);
        if (0 != id) {
            mIdHash->remove(id);
        }
    }
}

void LogicManager::onCloseConnection(const QString & ip)
{
    qDebug("C:  in LogicManager::%s, ip:%s", __func__, ip.toLatin1().data());
    mListSet->clearRecordInfo(ip);
    emit closeConnection(ip);
}

void LogicManager::onSendLogin(const QString & name)
{

    PRINT_ENTER_FUN;
    qDebug("log in");
    mSelf->setIp(Client::getIp());
    mSelf->setName(name);
    mXml->loginToXml(*mXmlData, name);
    emit sendServerData(*mXmlData);
}

void LogicManager::onReceivedServerData(const QByteArray & data)
{
    //qDebug("C:  in LogicManager::%s", __func__);
    mXml->read(NetParams::serverIp, data);
}


void LogicManager::onReceivedData(const QString & ip, const QByteArray & data)
{
    //qDebug("C:  in LogicManager::%s, ip:%s", __func__, ip.toLatin1().data());
    mXml->read(ip, data);
}

void LogicManager::onServerNotify(int code)
{
    qDebug("C:  in LogicManager::%s, code:%d", __func__, code);
    switch (code) {
        case '0': {
            emit networkStatusChanged(networkConnected);
            break;
        }
        default:{
            break;
        }
    }
}

void LogicManager::onNotify(const QString & ip, int code)
{
}

void LogicManager::onSendUserList(QList<userInfo> list)
{
    PRINT_ENTER_FUN;
    *mUserList = list;
    emit userListChanged(*mUserList);
}

void LogicManager::onSendRecordInfo(QString ip, recordInfo info)
{
    qDebug("C:  in LogicManager::%s, ip:%s", __func__, ip.toLatin1().data());
    mListSet->insertRecordInfo(ip, info);
    const QList<recordInfo> * list = mListSet->getRecordList(ip);
    emit messageUpdate(ip, *list);
    int code;
    if (info.getErrorCode() > 0) {
        code = ((unsigned short)info.getErrorCode() << 8) | xmlRecordReceived;
    } else {
        code = xmlRecordReceived;
    }
    mXml->statusToXml(*mXmlData, code);
    emit sendData(ip, *mXmlData);
}

void LogicManager::onSendStatus(QString ip, int code)
{
    qDebug("C:  in LogicManager::%s, code:%d", __func__, code);
    if (code < xmlLoginStatusEnd) {
        switch (code) {
            case xmlLoginSuccessful:
            case xmlRenameSuccessful: {
                mTimer->start(gPluseIntervalSecs);
                break;
            }
            default: {
                break;
            }
        }
        emit loginStatusReceived(eLoginStatus(code - 1 - xmlLoginStatusBase));
    } else if (code < xmlNetworkStatusEnd) {
        switch (code) {
            default:{
                break;
            }
        }
    } else {
        switch ((unsigned int)code & gTimerIdMask) {
            case xmlRecordReceived: {
                unsigned short id = ((unsigned int)code | gTimerIdMask) >> 8;
                if (mIdHash->contains(id)) {
                    QTimer * timer = mIdHash->value(id);
                    killTimer(timer);
                    mIdHash->remove(id);
                }
                break;
            }
            default:{
                break;
            }
        }
    }
}

void LogicManager::onSendPulse()
{
    mXml->pluseToXml(*mXmlData);
    emit sendServerData(*mXmlData);
}

void LogicManager::killTimer(QTimer * timer)
{
    timer->stop();
    delete timer;
    mRecordHash->remove(timer);
    mIpHash->remove(timer);
    mTimerList->removeOne(timer);
}
